package pl.edu.pw.polygen.modeler.server;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Observer;

import pl.edu.pw.polygen.modeler.server.util.ConverterService;
import pl.edu.pw.polygen.modeler.server.xml.Edge;
import pl.edu.pw.polygen.modeler.server.xml.MarshallService;
import pl.edu.pw.polygen.modeler.server.xml.PolygenData;
import pl.edu.pw.polygen.modeler.server.xml.Vertex;

import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.ui.AbsoluteLayout;
import com.vaadin.ui.ClientWidget;
import com.vaadin.ui.CustomComponent;

@ClientWidget(pl.edu.pw.polygen.modeler.client.workspace.Editor.class)
public class EditorServer extends CustomComponent {

	/**
	 * 
	 */
	private static final long serialVersionUID = 3694330071233246693L;
	private AbsoluteLayout mainLayout;
	private PolygenData polygenData;
	private boolean finished = false;
	private List<Observer> observers;

	private int editorWidth = 730;
	private int editorHeight = 600;

	private long getDataFlag = 0;
	private boolean uploadFlag = false;
	private boolean boundaries = false;

	public EditorServer() {
		super();
		observers = new ArrayList<Observer>();
		setSizeFull();
		setImmediate(true);
		buildMainLayout();
		setCompositionRoot(mainLayout);
	}

	public void addObserver(Observer o) {
		observers.add(o);
	}

	public void notifyObservers() {
		for (Observer o : observers) {
			o.update(null, null);
		}
	}

	private void buildMainLayout() {
		mainLayout = new AbsoluteLayout();
		mainLayout.setSizeFull();
	}

	public String getTag() {
		return "editorServer";
	}

	@Override
	public void changeVariables(Object source, Map<String, Object> variables) {
		super.changeVariables(source, variables);
		polygenData = new PolygenData();
		List<Vertex> vertexes = new ArrayList<Vertex>();
		List<Edge> edges;
		Vertex vertex;
		Edge edge;
		if (variables.containsKey("vertexAmount")) {
			final int vertexAmount = (Integer) variables.get("vertexAmount");
			System.out.println("vertexAmount = " + vertexAmount);
			for (int i = 0; i < vertexAmount; i++) {
				vertex = new Vertex();
				if (variables.containsKey("vertexId" + i)) {
					final int id = (Integer) variables.get("vertexId" + i);
					vertex.setId(id);
					System.out.print("x = " + id);
				}
				if (variables.containsKey("vertexX" + i)) {
					final double x = (Double) variables.get("vertexX" + i);
					vertex.setX(x);
					System.out.print("x = " + x);
				}
				if (variables.containsKey("vertexY" + i)) {
					final double y = (Double) variables.get("vertexY" + i);
					vertex.setY(y);
					System.out.print("y = " + y);
				}
				if (variables.containsKey("vertexT" + i)) {
					final String type = (String) variables.get("vertexT" + i);
					vertex.setType(type);
					System.out.println("type = " + type);
				}
				if (variables.containsKey("vertexBoundary" + i)) {
					final int boundary = (Integer) variables.get("vertexBoundary" + i);
					vertex.setBoundary(boundary);
					System.out.println("boundary = " + boundary);
				}
				vertex.setValue(0.1);

				edges = new ArrayList<Edge>();
				if (variables.containsKey("edgesAmount" + i)) {
					final int edgesAmount = (Integer) variables
							.get("edgesAmount" + i);
					System.out.println("edgesAmount = " + edgesAmount);
					for (int j = 0; j < edgesAmount; j++) {
						edge = new Edge();
						if (variables.containsKey("edgeB" + i + "_" + j)) {
							final int edgeB = (Integer) variables.get("edgeB" + i
									+ "_" + j);
							edge.setBegin(edgeB);
							System.out.println("begin = " + edgeB);
						}
						if (variables.containsKey("edgeE" + i + "_" + j)) {
							final int edgeE = (Integer) variables.get("edgeE" + i
									+ "_" + j);
							edge.setEnd(edgeE);
							System.out.println("end   = " + edgeE);
						}
						if (variables.containsKey("edgeBoundary" + i + "_" + j)) {
							final int edgeBoundary = (Integer) variables.get("edgeBoundary" + i
									+ "_" + j);
							edge.setBoundary(edgeBoundary);
							System.out.println("edgeBoundary   = " + edgeBoundary);
						}
						
						if (variables.containsKey("edgeT" + i + "_" + j)) {
							final String edgeT = (String) variables.get("edgeT"
									+ i + "_" + j);
							System.out.println("type  = " + edgeT);
							edge.setType(edgeT);

							if ("SPLAIN".equals(edgeT)) {
								if (variables.containsKey("edgeCA" + i + "_"
										+ j)) {
									final int edgeCA = (Integer) variables
											.get("edgeCA" + i + "_" + j);
									edge.setControlA(edgeCA);
									System.out.println("conA = " + edgeCA);
								}
								if (variables.containsKey("edgeCB" + i + "_"
										+ j)) {
									final int edgeCB = (Integer) variables
											.get("edgeCB" + i + "_" + j);
									edge.setControlB(edgeCB);
									System.out.println("conB = " + edgeCB);
								}
								if (variables.containsKey("edgeStep" + i + "_"
										+ j)) {
									final double edgeStep = (Double) variables
											.get("edgeStep" + i + "_" + j);
									edge.setStep(edgeStep);
									System.out.println("edgeStep = " + edgeStep);
								}
							}
						}
						edges.add(edge);
					}
				}
				vertex.setEdges(edges);
				vertexes.add(vertex);
			}

		}
		polygenData.setVertexes(vertexes);
		finished = true;
		notifyObservers();
	}

	@Override
	public void paintContent(PaintTarget target) throws PaintException {
		super.paintContent(target);
		
		
		
		target.addVariable(this, "editorWidth", editorWidth);
		target.addVariable(this, "editorHeight", editorHeight);
		target.addVariable(this, "boundaries", this.boundaries);
		target.addVariable(this, "getGraphData", getDataFlag);
		
		if (uploadFlag == true) {
			target.addVariable(this, "uploadFlag", uploadFlag);
			List<Vertex> vertexes = polygenData.getVertexes();
			target.addVariable(this, "vertexAmount", vertexes.size());
			for (int i = 0; i < vertexes.size(); i++) {
				Vertex vertex = vertexes.get(i);
				target.addVariable(this, "vertexId"+i, vertex.getId());
				target.addVariable(this, "vertexX"+i, vertex.getX());
				target.addVariable(this, "vertexY"+i, vertex.getY());
				target.addVariable(this, "vertexType"+i, vertex.getType());
				target.addVariable(this, "vertexBoundary"+i, vertex.getBoundary());
			}
			
			for(int i = 0; i < vertexes.size();i++){
				Vertex vertex = vertexes.get(i);
				List<Edge> edges = vertex.getEdges();
				target.addVariable(this, "edgesAmount"+ i, edges.size());
				for(int j=0;j<edges.size();j++){
					Edge edge = edges.get(j);
					target.addVariable(this, "edgeB"+i+"_"+j, edge.getBegin());
					target.addVariable(this, "edgeE"+i+"_"+j, edge.getEnd());
					target.addVariable(this, "edgeT"+i+"_"+j, edge.getType());
					target.addVariable(this, "edgeBoundary"+i+"_"+j, edge.getBoundary());
					if("SPLAIN".equals(edge.getType())){
						target.addVariable(this, "edgeCA"+i+"_"+j, edge.getControlA());
						target.addVariable(this, "edgeCB"+i+"_"+j, edge.getControlB());
						target.addVariable(this, "edgeStep"+i+"_"+j, edge.getStep());
					}
				}
			}
		}
		
		
		
		uploadFlag = false;
		getDataFlag = 0;
	}

	public void setNewSize(int width, int height) {
		editorWidth = width;
		editorHeight = height;
		requestRepaint();
	}

	public void getGraphData() {
		getDataFlag = 1L;
		requestRepaint();
	}

	public void uploadData(String data) {
		if(data!=null){
			MarshallService marshallService = new MarshallService();
			this.polygenData = marshallService.unmarshall(data);
			uploadFlag = true;
			requestRepaint();
			
		}
	}

	public synchronized String getPolygenData() {
		finished = false;
		MarshallService marshallService = new MarshallService();
		return marshallService.marshall(polygenData);
	}

	public synchronized boolean isFinished() {
		return finished;
	}

	public String loadFromPolyFile(File file) {
		if(file!=null){
			System.out.println("parsowanko");
			PolygenData polygenData = ConverterService.convertToPolygenData(file);
			file.delete();
			MarshallService marshallService = new MarshallService();
			return marshallService.marshall(polygenData);
		}
		return null;
	}

	public void showBoundaries(boolean value) {
		this.boundaries = value;
		requestRepaint();
	}

}
